package com.zhangquancheng.shirodemo.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Author: zhangquancheng
 * @Description: shiro配置类
 * @Date: 2022/7/14 1:07 下午
 */
@Configuration
@Lazy
public class ShiroConfig {

//    /**
//     * 异常映射解析器
//     *
//     * SimpleMappingExceptionResolver 启动是在tomcat启动的时候执行
//     * MyExceptionHandler 每次url访问的时候启动
//     */
//    @Bean
//    public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
//        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
//        Properties properties = new Properties();
//        /*未授权处理页*/
//        properties.setProperty("org.apache.shiro.authz.UnauthorizedException", "/403");
//        /*⾝份没有验证*/
//        properties.setProperty("org.apache.shiro.authz.UnauthenticatedException", "/toLogin");
//        resolver.setExceptionMappings(properties);
//        return resolver;
//    }

//    /**
//     * Session Manager：会话管理
//     * 即用户登录后就是一次会话，在没有退出之前，它的所有信息都在会话中；
//     * 会话可以是普通JavaSE环境的，也可以是如Web环境的；
//     * 管理所有Subject的session包括创建、维护、删除、失效、验证等工作
//     *
//     * DefaultSessionManager 用于JavaSE环境
//     * ServletContainerSessionManager 用于Web环境，直接使用servlet容器的会话。
//     * DefaultWebSessionManager 用于web环境自己维护会话
//     */
//    @Bean("sessionManager")
//    public SessionManager sessionManager(){
//        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
//        sessionManager.
//        //设置session过期时间
//        sessionManager.setGlobalSessionTimeout(60 * 60 * 1000);
//        sessionManager.setSessionValidationSchedulerEnabled(true);
//        // 去掉shiro登录时url里的JSESSIONID
//        sessionManager.setSessionIdUrlRewritingEnabled(false);
//        return sessionManager;
//    }


    /**
     * ShiroFilter是整个Shiro的入口点，用于拦截需要安全控制的请求进行处理
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilter.setSecurityManager(securityManager);
        //登陆请求
        shiroFilter.setLoginUrl("/toLogin");
        /**
         * 拦截设置
         * anon:无需认证就可以访问
         * authc:必须认证了才可以访问
         * user:必须拥有记住我功能才能用
         * perms:拥有对某个资源的权限才能访问
         * role:拥有某个角色权限才能访问
         * */
        Map<String, String> filterMap = new LinkedHashMap<>();
        //当前请求地址必须认证后访问
        filterMap.put("/user/login","anon");
        filterMap.put("/user/*","authc");
        shiroFilter.setFilterChainDefinitionMap(filterMap);
        return shiroFilter;
    }

    /**
     * SecurityManager：安全管理器
     */
    @Bean(name = "securityManager")
//    public DefaultWebSecurityManager securityManager(@Qualifier("sessionManager") SessionManager sessionManager,@Qualifier("userRealm") UserRealm userRealm) {
    public DefaultWebSecurityManager securityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置realm
        securityManager.setRealm(userRealm);
        //设置会话管理sessionManager
//        securityManager.setSessionManager(sessionManager);
        return securityManager;
    }

    //第一步：创建realm对象，并被Spring托管
    @Bean(name = "userRealm")
    public UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        //指定处理加解密的匹配工具类
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
        hashedCredentialsMatcher.setHashIterations(1);
        userRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        return userRealm;
    }

//-------------------------------------开启shiro注解

    /**
     * 管理Shiro中一些bean的生命周期
     */
    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 扫描上下文，寻找所有的Advistor(通知器）
     * 将这些Advisor应用到所有符合切入点的Bean中。
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }

    /**
     * 匹配所有加了 Shiro 认证注解的方法
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }


    //-------------------------------------thymeleaf和shiro标签配合
    /**
     * 配置ShiroDialect:用于thymeleaf和shiro标签配合使用
     */
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
}
